<?php namespace xlx;

use Workerman\Connection\TcpConnection;
use \Workerman\Events\EventInterface;
 
class AChannel extends \xlx\lib\LocalActor
{ 
    function __construct($pid)
    {  
        parent::__construct($pid); 
        \xlx\Danboo::$data_server['TRAPEXIT'][$this->self()] = false;
        //\xlx\Danboo::$data_server['STACK'][$this->self()] = $stack; 
    }
    function __destruct()
    { 
        \xlx\Danboo::$conn_server->send(['CLOSE',$this->self()]);
        unset(\xlx\Danboo::$data_server['TRAPEXIT'][$this->self()]);
        //unset(\xlx\Danboo::$data_server['STACK'][$this->self()]);
        parent::__destruct();
    }

    ////////////// client ///////////////// 
    /** 
     * @param \xlx\AChannel $out_actor
     * @param mixed $out_stack
     * @return string
     */
    public static function make(&$out_actor,&$out_stack) { 
        if (empty(\xlx\Danboo::$conn_server)) {//fork 进程 会保留父进程 socket
            \xlx\Danboo::connectServer();//echo "\n[connectServer]\n";
        }   
        //bldd
        $tick = self::tick();
        //$this->hash = $hash; ;//保存当前协调程序（终止协调程序用 
        $out_stack = \xlx\co\self(true);   
        \xlx\Danboo::$conn_server->send(['NEW',$out_stack->__hash,$tick]); 
        //echo "\r%%";
        //$this->__REF__ = ;
        // $out_stack = \xlx\co\self();  
        // $d = yield \xlx\AChannel::make( $out_stack->__hash  ); 
        

        \xlx\Danboo::$data_server['NEW'][$tick] = new \React\Promise\Deferred;  
        $pid = yield \xlx\Danboo::$data_server['NEW'][$tick]->promise();
        //echo "\r~~";
        //->then(function($pid)use($fn,$tick){
        //unset(\xlx\Danboo::$data_server['NEW'][$tick]);
        //$out_actor = new self(  $gen ,$pid );  
        $out_actor = \xlx\lib\WeakRef::share(new self($pid),$pid); 
        //return $actor;
        //return $actor;//->then(function()use($actor){return $actor;});
        //}); 
        return $pid;
    }


    function call($data)
    {
        $data[] = $this->self();
        $data[] = $tick = self::tick();
        \xlx\Danboo::$conn_server->send($data);
        return $this->receive(function ($data) use ($tick) { 
            if (\is_array($data) && $data[0] == $tick) {
                if ($data[2]== 'err') {
                    throw new \Exception($data[3], 1);
                }else{
                    return $data[2];
                }
            }
        });
    }

    static function tick($add = 1)
    {
        static $i;
        return $i+=$add ;
    }
    //////////// method ///////////////// 

    public function send($to, $msg)
    {   
        if($actor = \xlx\lib\WeakRef::take($to)){
            return parent::send($actor,$msg);
        }else{ 
            $data[] = 'SEND';
            $data[] = $to;
            $data[] = $msg;
            $data[] = $this->self();
            $data[] = $tick = self::tick();
            \xlx\Danboo::$conn_server->send($data);
            return ['ok'];
        } 
    }

    public function register($atom)
    {
        //$this->registername = $atom;
        return $this->call(['REGISTER',$atom]);
    }
    public function unregister()
    {
        ///unset($this->registername);
        return $this->call(['UNREGISTER',$atom]);
    }

    public function monitor($to)
    {
        return $this->call(['MONITOR',$to]);
    }
    public function demonitor($to)
    {
        return $this->call(['DEMONITOR',$to]);
    }
 
    public function link($to,$class=null)
    {
        return $this->call(['LINK',$to,$class]);
    }
    public function unlink($to)
    {
        return $this->call(['UNLINK',$to]);
    }

    public function whereis($atom)
    {
        return $this->call(['WHEREIS',$atom]);
    }

    public function spawn($fn,$args=[]){
        if($fn instanceof \Closure){
            $fn = (serialize(new \Opis\Closure\SerializableClosure($fn)) );
        }
        return $this->call(['SPAWN',$fn,$args]); 
    }

    public function spawn_link($fn,$args=[]){
        $pid = yield $this->spawn($fn,$args);
        yield $this->link($pid); 
        return $pid;
    }
   
    public function spawn_monitor($fn,$args=[]){
        $pid = yield $this->spawn($fn,$args);
        yield $this->monitor($pid); 
        return $pid;
    }

    public function service($fn,$args=[]){

    }
   

    public function trap_exit($bool)
    {
        \xlx\Danboo::$data_server['TRAPEXIT'][$this->self()]=$bool;
    }

}

